﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EvoAlgLib
{
    class TSPIndividual: GenArrayIndividual
    {
        protected static int LENGTH = 29;
        private int start_end_city = 22;
        private int[,] _dists = {{0,625,567,1183,918,983,1038,383,420,881,852,914,635,230,100,418,620,888,190,251,40,673,700,250,994,706,326,690},
                                {625,0,190,820,808,1040,740,703,1021,963,639,1002,423,836,702,652,1162,520,447,855,587,671,796,450,630,1263,308,540},
                                {567,190,0,630,610,850,550,366,765,771,441,805,220,770,630,453,962,330,389,797,528,474,560,441,440,1064,240,350},
                                {1183,820,630,0,377,722,401,901,867,480,396,812,635,1019,1258,822,969,300,1004,1412,1144,614,605,1057,240,1071,856,489},
                                {918,808,610,377,0,350,120,641,545,109,151,450,613,697,1006,562,610,335,1078,1160,940,353,240,1138,181,760,843,251},
                                {983,1040,850,722,350,0,471,711,571,280,492,110,683,761,1060,631,514,670,1143,1224,1005,423,290,1202,634,620,1106,526},
                                {1038,740,550,401,120,471,0,761,665,229,284,570,733,817,1126,682,730,320,1198,1280,1060,473,363,1258,206,880,884,378},
                                {383,703,366,901,641,711,761,0,345,608,513,642,180,210,470,100,554,627,373,624,405,300,436,433,655,635,400,404},
                                {420,1021,765,867,545,571,665,345,0,520,479,502,433,190,520,180,200,658,576,658,438,299,310,636,621,323,728,418},
                                {881,963,771,480,109,280,229,608,520,0,260,300,580,659,968,523,580,438,1040,1122,902,315,210,1099,284,687,998,424},
                                {852,639,441,396,151,492,284,513,479,260,0,424,310,631,940,434,581,190,823,1093,874,225,200,875,150,682,674,82},
                                {914,1002,805,812,450,110,570,642,502,300,424,0,614,692,1002,563,418,602,1074,1155,936,340,220,1134,565,525,1038,450},
                                {635,423,220,635,613,683,733,180,433,580,310,614,0,390,723,230,772,341,446,877,586,272,408,498,459,873,297,210},
                                {230,836,770,1019,697,761,817,210,190,659,631,692,390,0,319,210,404,809,391,470,253,499,479,451,777,485,537,603},
                                {100,702,630,1258,1006,1060,1126,470,520,968,940,1002,723,319,0,506,700,964,257,190,125,761,770,317,1082,794,403,865},
                                {418,652,453,822,562,631,682,100,180,523,434,563,230,210,506,0,426,547,485,659,440,210,357,544,576,507,500,250},
                                {620,1162,962,969,610,514,730,554,200,580,581,418,772,404,700,426,0,760,785,866,647,512,370,845,723,150,931,615},
                                {888,520,330,300,335,670,320,627,658,438,190,602,341,809,964,547,760,0,710,1118,850,350,390,762,110,861,562,200},
                                {190,447,389,1004,1078,1143,1198,373,576,1040,823,1074,446,391,257,485,785,710,0,411,150,664,860,62,828,866,160,731},
                                {251,855,797,1412,1160,1224,1280,624,658,1122,1093,1155,877,470,190,659,866,1118,411,0,278,890,941,470,1235,784,556,1019},
                                {40,587,528,1144,940,1005,1060,405,438,902,874,936,586,253,125,440,647,850,150,278,0,695,722,202,1016,728,288,800},
                                {673,671,474,614,353,423,473,300,299,315,225,340,272,499,761,210,512,350,664,890,695,0,120,724,367,613,707,127},
                                {700,796,560,605,240,290,363,436,310,210,200,220,408,479,770,357,370,390,860,941,722,120,0,919,359,520,831,252},
                                {250,450,441,1057,1138,1202,1258,433,636,1099,875,1134,498,451,317,544,845,762,62,470,202,724,919,0,880,925,200,783},
                                {994,630,440,240,181,634,206,655,621,284,150,565,459,777,1082,576,723,110,828,1235,1016,367,359,880,0,824,680,242},
                                {706,1263,1064,1071,760,620,880,635,323,687,682,525,873,485,794,507,150,861,866,784,728,613,520,925,824,0,1011,716},
                                {326,308,240,856,843,1106,884,400,728,998,674,1038,297,537,403,500,931,562,160,556,288,707,831,200,680,1011,0,583},
                                {690,540,350,489,251,526,378,404,418,424,82,450,210,603,865,250,615,200,731,1019,800,127,252,783,242,716,583,0}};


        public TSPIndividual(TSPIndividual other) : base (other) { }

        public TSPIndividual (double mutate) : base(mutate)
        {

            int length = this._dists.GetLength(0) + 1;
            this.genotype = new int[length];

            this.genotype[0] = this.start_end_city;
            this.genotype[length - 1] = this.start_end_city;


            int k = 0;
            for (int i = 1; i < length - 1; i++)
            {
                if (k == this.start_end_city)
                    k++;
                this.genotype[i] = k++;
            }

            for (int i = length - 2; i > 0; i--)
            {
                int j = LibStatics.getRandomizer().Next(i) + 1;
                int tmp = this.genotype[j];
                this.genotype[j] = this.genotype[i];
                this.genotype[i] = tmp;
            }
        }

        protected override void calcFit()
        {
            this.fitness = 0;
            for (int i = 0; i < this.genotype.Count() - 1; i++)
            {
                this.fitness += this._dists[this.genotype[i], this.genotype[i + 1]];
            }
            this.fitness = 1.0 / this.fitness;
        }

        protected override void slotMutate(int i) { }

        public override Individual mutate()
        {
            double p = LibStatics.getRandomizer().NextDouble();
            if (p < this.p_mutate)
            {
                int r1 = LibStatics.getRandomizer().Next(this.genotype.Count() - 2) + 1;
                int r2 = LibStatics.getRandomizer().Next(this.genotype.Count() - 2) + 1;
                int tmp = this.genotype[r1];
                this.genotype[r1] = this.genotype[r2];
                this.genotype[r2] = tmp;
            }
            this.needsCalcFit = true;
            return this;
        }

        public override string plotDisplay()
        {
            StringBuilder sb = new StringBuilder();
            double f = 1.0 / this.fitness;
            sb.Append(f);
            sb.Append(" [ ");
            for (int i = 0; i < this.genotype.Length; i++)
            {
                sb.Append(this.genotype[i]);
                if (i < this.genotype.Length - 1)
                {
                    sb.Append(", ");
                }
            }
            sb.Append(" ] ");
            return sb.ToString();
        }
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("[ ");
            for (int i = 0; i < this.genotype.Length; i++)
            {
                sb.Append(this.genotype[i]);
                if (i < this.genotype.Length - 1)
                {
                    sb.Append(", ");
                }
            }
            sb.Append(" ]");
            return sb.ToString();
        }
    }
}
